#!/usr/bin/env python3
"""
SkyWalking 数据导出与分析 Dashboard
主要功能：CSV 批量导出
辅助功能：简单的趋势图分析
"""

import os
import sys
from pathlib import Path
from datetime import datetime, timedelta, timezone
from io import BytesIO
import zipfile

import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from dotenv import load_dotenv

# 添加当前目录到 Python 路径
sys.path.insert(0, str(Path(__file__).parent))

from database.db_manager import DatabaseManager
from dashboard.data_access import DashboardDataAccess


# ==================== 配置 ====================

st.set_page_config(
    page_title="SkyWalking 数据导出平台",
    page_icon="📦",
    layout="wide",
    initial_sidebar_state="expanded"
)

# 加载配置
env_path = Path(__file__).parent / "config.env"
if env_path.exists():
    load_dotenv(env_path)

DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///data/skywalking_data.db')


# ==================== 初始化 ====================

@st.cache_resource
def init_data_access():
    """初始化数据访问层（单例）"""
    db_manager = DatabaseManager(DATABASE_URL, echo=False)
    return DashboardDataAccess(db_manager)


data_access = init_data_access()


# ==================== 辅助函数 ====================

def format_datetime_utc8(dt):
    """格式化日期时间（转换为 UTC+8）"""
    if pd.isna(dt) or dt is None:
        return "N/A"
    if dt.tzinfo is None:
        dt = dt.replace(tzinfo=timezone.utc)
    dt_utc8 = dt.astimezone(timezone(timedelta(hours=8)))
    return dt_utc8.strftime("%Y-%m-%d %H:%M:%S")


def create_zip_from_dataframes(dfs_dict):
    """
    从多个 DataFrame 创建 ZIP 文件
    
    Args:
        dfs_dict: {文件名: DataFrame}
    
    Returns:
        BytesIO: ZIP 文件内容
    """
    zip_buffer = BytesIO()
    
    with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
        for filename, df in dfs_dict.items():
            if not df.empty:
                csv_buffer = BytesIO()
                df.to_csv(csv_buffer, index=False, encoding='utf-8-sig')
                zip_file.writestr(filename, csv_buffer.getvalue())
    
    zip_buffer.seek(0)
    return zip_buffer


# ==================== 主界面 ====================

st.title("📦 SkyWalking 数据导出与分析平台")
st.markdown("---")

# ==================== 第一部分：数据导出区域 ====================

st.header("📤 数据导出")

col1, col2 = st.columns([2, 1])

with col1:
    # 服务选择
    services = data_access.get_all_services()
    
    if not services:
        st.warning("⚠️ 暂无服务数据，请等待数据采集")
        st.stop()
    
    service_options = {"[全部服务]": None}
    service_options.update({s['name']: s['name'] for s in services})
    
    selected_service_display = st.selectbox(
        "选择服务（用于筛选导出数据）",
        options=list(service_options.keys()),
        index=0,
        help="选择 [全部服务] 将导出所有服务的数据"
    )
    selected_service_name = service_options[selected_service_display]

with col2:
    # 时间范围选择
    time_preset = st.selectbox(
        "时间范围",
        options=['1h', '6h', '24h', '7d', '30d', 'all'],
        index=5,  # 默认 all
        format_func=lambda x: {
            '1h': '最近 1 小时',
            '6h': '最近 6 小时',
            '24h': '最近 24 小时',
            '7d': '最近 7 天',
            '30d': '最近 30 天',
            'all': '全部历史数据'
        }[x],
        help="选择要导出的时间范围"
    )

# 计算时间范围
if time_preset == 'all':
    start_time = None
    end_time = None
    time_range_display = "全部历史数据"
else:
    start_time, end_time = data_access.get_time_range_preset(time_preset)
    time_range_display = f"{format_datetime_utc8(start_time)} ~ {format_datetime_utc8(end_time)}"

st.info(f"📅 导出范围：**{selected_service_display}** | ⏰ 时间：**{time_range_display}**")

# 导出按钮区域
st.markdown("### 导出选项")

col1, col2, col3, col4 = st.columns(4)

with col1:
    if st.button("📥 导出服务数据", use_container_width=True, type="primary"):
        with st.spinner("正在导出服务数据..."):
            services_df, metrics_df = data_access.export_services_to_csv(
                service_name=selected_service_name,
                start_time=start_time,
                end_time=end_time
            )
            
            if services_df.empty and metrics_df.empty:
                st.warning("⚠️ 没有符合条件的服务数据")
            else:
                # 创建 ZIP 文件
                zip_data = create_zip_from_dataframes({
                    'services.csv': services_df,
                    'service_metrics.csv': metrics_df
                })
                
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                st.download_button(
                    label="⬇️ 下载服务数据 (ZIP)",
                    data=zip_data,
                    file_name=f"skywalking_services_{timestamp}.zip",
                    mime="application/zip",
                    use_container_width=True
                )
                
                st.success(f"✅ 服务列表: {len(services_df)} 条 | 服务指标: {len(metrics_df)} 条")

with col2:
    if st.button("📥 导出端点数据", use_container_width=True, type="primary"):
        with st.spinner("正在导出端点数据..."):
            endpoints_df, ep_metrics_df = data_access.export_endpoints_to_csv(
                service_name=selected_service_name,
                start_time=start_time,
                end_time=end_time
            )
            
            if endpoints_df.empty and ep_metrics_df.empty:
                st.warning("⚠️ 没有符合条件的端点数据")
            else:
                zip_data = create_zip_from_dataframes({
                    'endpoints.csv': endpoints_df,
                    'endpoint_metrics.csv': ep_metrics_df
                })
                
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                st.download_button(
                    label="⬇️ 下载端点数据 (ZIP)",
                    data=zip_data,
                    file_name=f"skywalking_endpoints_{timestamp}.zip",
                    mime="application/zip",
                    use_container_width=True
                )
                
                st.success(f"✅ 端点列表: {len(endpoints_df)} 条 | 端点指标: {len(ep_metrics_df)} 条")

with col3:
    if st.button("📥 导出 Trace 数据", use_container_width=True, type="primary"):
        with st.spinner("正在导出 Trace 数据..."):
            traces_df = data_access.export_traces_to_csv(
                service_name=selected_service_name,
                start_time=start_time,
                end_time=end_time
            )
            
            if traces_df.empty:
                st.warning("⚠️ 没有符合条件的 Trace 数据")
            else:
                csv_buffer = BytesIO()
                traces_df.to_csv(csv_buffer, index=False, encoding='utf-8-sig')
                csv_buffer.seek(0)
                
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                st.download_button(
                    label="⬇️ 下载 Trace 数据 (CSV)",
                    data=csv_buffer,
                    file_name=f"skywalking_traces_{timestamp}.csv",
                    mime="text/csv",
                    use_container_width=True
                )
                
                st.success(f"✅ Trace 记录: {len(traces_df)} 条")

with col4:
    if st.button("📥 导出全部数据", use_container_width=True, type="secondary"):
        with st.spinner("正在导出全部数据（可能需要较长时间）..."):
            # 导出所有数据
            services_df, metrics_df = data_access.export_services_to_csv(
                service_name=selected_service_name,
                start_time=start_time,
                end_time=end_time
            )
            
            endpoints_df, ep_metrics_df = data_access.export_endpoints_to_csv(
                service_name=selected_service_name,
                start_time=start_time,
                end_time=end_time
            )
            
            traces_df = data_access.export_traces_to_csv(
                service_name=selected_service_name,
                start_time=start_time,
                end_time=end_time
            )
            
            # 创建包含所有数据的 ZIP
            zip_data = create_zip_from_dataframes({
                'services.csv': services_df,
                'service_metrics.csv': metrics_df,
                'endpoints.csv': endpoints_df,
                'endpoint_metrics.csv': ep_metrics_df,
                'traces.csv': traces_df
            })
            
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            st.download_button(
                label="⬇️ 下载全部数据 (ZIP)",
                data=zip_data,
                file_name=f"skywalking_all_data_{timestamp}.zip",
                mime="application/zip",
                use_container_width=True
            )
            
            total_records = len(services_df) + len(metrics_df) + len(endpoints_df) + len(ep_metrics_df) + len(traces_df)
            st.success(f"✅ 总计: {total_records:,} 条记录")

st.markdown("---")

# ==================== 第二部分：统计分析区域（辅助） ====================

st.header("📊 数据统计分析")

# 选择用于分析的服务（必须选择单个服务）
analysis_services = {s['name']: s['service_id'] for s in services}
analysis_service_name = st.selectbox(
    "选择服务进行分析",
    options=list(analysis_services.keys()),
    index=0,
    help="统计分析功能需要选择单个服务"
)
analysis_service_id = analysis_services[analysis_service_name]

# 分析时间范围
analysis_time_preset = st.selectbox(
    "分析时间范围",
    options=['1h', '6h', '24h', '7d', '30d'],
    index=2,  # 默认 24h
    format_func=lambda x: {
        '1h': '最近 1 小时',
        '6h': '最近 6 小时',
        '24h': '最近 24 小时',
        '7d': '最近 7 天',
        '30d': '最近 30 天'
    }[x]
)

analysis_start, analysis_end = data_access.get_time_range_preset(analysis_time_preset)

# 创建 Tabs
tabs = st.tabs(["📈 服务指标趋势", "🔗 端点指标趋势", "🔍 Trace 分析"])

# ==================== Tab 1: 服务指标趋势 ====================

with tabs[0]:
    st.subheader(f"服务: {analysis_service_name}")
    
    # 获取服务指标历史
    metrics_history = data_access.get_service_metrics_history(
        analysis_service_id,
        analysis_start,
        analysis_end
    )
    
    if not metrics_history:
        st.info("📭 该时间范围内没有服务指标数据")
    else:
        # 为每个指标创建折线图
        metric_names = list(set([m['metric_name'] for m in metrics_history]))
        
        for metric_name in metric_names:
            metric_data = [m for m in metrics_history if m['metric_name'] == metric_name]
            
            if metric_data:
                df = pd.DataFrame(metric_data)
                df['timestamp_utc8'] = pd.to_datetime(df['timestamp']).dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai')
                
                fig = px.line(
                    df,
                    x='timestamp_utc8',
                    y='value',
                    title=f"指标: {metric_name}",
                    labels={'timestamp_utc8': '时间 (UTC+8)', 'value': '值'}
                )
                
                fig.update_layout(
                    height=300,
                    showlegend=False,
                    hovermode='x unified'
                )
                
                st.plotly_chart(fig, use_container_width=True)

# ==================== Tab 2: 端点指标趋势 ====================

with tabs[1]:
    st.subheader(f"服务: {analysis_service_name}")
    
    # 获取端点列表
    endpoints = data_access.get_endpoints_by_service(analysis_service_id)
    
    if not endpoints:
        st.info("📭 该服务没有端点数据")
    else:
        # 选择端点
        endpoint_options = {e['endpoint_name']: e['endpoint_id'] for e in endpoints}
        selected_endpoint_name = st.selectbox(
            "选择端点",
            options=list(endpoint_options.keys()),
            index=0
        )
        selected_endpoint_id = endpoint_options[selected_endpoint_name]
        
        # 获取端点指标历史
        endpoint_metrics = data_access.get_endpoint_metrics_history(
            selected_endpoint_id,
            analysis_start,
            analysis_end
        )
        
        if not endpoint_metrics:
            st.info("📭 该端点在此时间范围内没有指标数据")
        else:
            # 为每个指标创建折线图
            metric_names = list(set([m['metric_name'] for m in endpoint_metrics]))
            
            for metric_name in metric_names:
                metric_data = [m for m in endpoint_metrics if m['metric_name'] == metric_name]
                
                if metric_data:
                    df = pd.DataFrame(metric_data)
                    df['timestamp_utc8'] = pd.to_datetime(df['timestamp']).dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai')
                    
                    fig = px.line(
                        df,
                        x='timestamp_utc8',
                        y='value',
                        title=f"端点指标: {metric_name}",
                        labels={'timestamp_utc8': '时间 (UTC+8)', 'value': '值'}
                    )
                    
                    fig.update_layout(
                        height=300,
                        showlegend=False,
                        hovermode='x unified'
                    )
                    
                    st.plotly_chart(fig, use_container_width=True)

# ==================== Tab 3: Trace 分析 ====================

with tabs[2]:
    st.subheader(f"服务: {analysis_service_name}")
    
    # 获取 Trace 统计
    trace_stats = data_access.get_error_trace_statistics(
        analysis_service_id,
        analysis_start,
        analysis_end
    )
    
    if not trace_stats:
        st.info("📭 该时间范围内没有 Trace 数据")
    else:
        col1, col2, col3, col4 = st.columns(4)
        
        with col1:
            st.metric("总 Trace 数", f"{trace_stats['total_traces']:,}")
        
        with col2:
            st.metric("错误数", f"{trace_stats['error_traces']:,}")
        
        with col3:
            st.metric("成功率", f"{trace_stats['success_rate']:.2f}%")
        
        with col4:
            if trace_stats['avg_duration']:
                st.metric("平均响应时间", data_access.format_duration(trace_stats['avg_duration']))
            else:
                st.metric("平均响应时间", "N/A")
        
        st.markdown("---")
        
        # 获取 Trace 列表（最近50条）
        traces_list = data_access.get_traces_list(
            analysis_service_id,
            analysis_start,
            analysis_end,
            limit=50
        )
        
        if traces_list:
            st.subheader("最近 50 条 Trace")
            
            # 转换为 DataFrame 用于显示
            traces_display = []
            for t in traces_list:
                traces_display.append({
                    'Trace ID': t['trace_id'][:16] + '...',  # 缩短显示
                    '端点': t['endpoint_names'][:50] if t['endpoint_names'] else 'N/A',
                    '响应时间': data_access.format_duration(t['duration']),
                    '开始时间 (UTC+8)': format_datetime_utc8(t['start_time']),
                    '状态': '❌ 错误' if t['is_error'] else '✅ 成功'
                })
            
            traces_df = pd.DataFrame(traces_display)
            st.dataframe(traces_df, use_container_width=True, height=400)

# ==================== 页脚 ====================

st.markdown("---")
st.markdown(
    """
    <div style='text-align: center; color: #888; font-size: 14px;'>
        SkyWalking 数据导出与分析平台 | 
        数据库: SQLite | 
        采集频率: 每30分钟
    </div>
    """,
    unsafe_allow_html=True
)
